package kbpost

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/utils/pointy"
	"mall/service/backend/rpc/backendclient"
	"mall/service/blog/rpc/blogclient"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/api/internal/utils/parse"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetEntryListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetEntryListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetEntryListLogic {
	return &GetEntryListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetEntryListLogic) GetEntryList(
	req *types.GetEntryListReq,
	headers *[]*types.Header,
) (*types.GetEntryListResp, error) {
	userId := jwt.GetUserId(l.ctx)

	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	platformId := globalkey.ThirdPartyPlatformWechatMini

	if req.Type != nil && *req.Type == 1 {
		return l.getSectionEntryList(headers, page, pageSize, userId, platformId)
	}

	return l.getEntryList(page, pageSize, userId, platformId, req.SectionId, req.Sticky)
}

func (l *GetEntryListLogic) getSectionEntryList(
	headers *[]*types.Header,
	page uint64,
	pageSize uint64,
	userId uint64,
	platformId uint32,
) (resp *types.GetEntryListResp, err error) {
	preload := "sectionPost:SectionId,PostId"
	eagerLoad := "sectionPost:section"
	preload += ";section:Id,Title,Subtitle,PicUrl"
	preFilterEntity := "section"

	var filters []string
	filters = append(filters, "PostType,equalTo:"+strconv.FormatInt(int64(globalkey.SettingSectionTypeEntryIndex), 10))
	var preFilters []string
	preFilters = append(preFilters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusEnabled), 10))
	preFilters = append(preFilters, "Type,equalTo:"+strconv.FormatInt(int64(globalkey.SettingSectionTypeEntryIndex), 10))
	res, err := l.svcCtx.BackendRpc.GetSectionPostList(l.ctx, &backendclient.BaseListReq{
		Offset:          uint32((page - 1) * pageSize),
		Limit:           uint32(pageSize),
		Preload:         pointy.GetPointer(preload),
		EagerLoad:       pointy.GetPointer(eagerLoad),
		Filter:          pointy.GetPointer(strings.Join(filters, ";")),
		PreFilterEntity: pointy.GetPointer(preFilterEntity),
		PreFilter:       pointy.GetPointer(strings.Join(preFilters, ";")),
		VisitorId:       pointy.GetPointer(userId),
		PlatformId:      pointy.GetPointer(platformId),
	})
	if err != nil {
		return nil, err
	}

	var hasNextPage bool
	var hasPreviousPage bool
	if res.HasNextPage != nil && *res.HasNextPage > 0 {
		hasNextPage = true
	}
	if res.HasPreviousPage != nil && *res.HasPreviousPage > 0 {
		hasPreviousPage = true
	}

	resp = &types.GetEntryListResp{
		BaseListInfo: types.BaseListInfo{
			HasNextPage:     hasNextPage,
			HasPreviousPage: hasPreviousPage,
		},
	}

	if len(res.List) > 0 {
		var pids []string
		postIdMap := make(map[uint64]struct{})
		var section *backendclient.SectionInfo
		for _, v := range res.List {
			if v.PostId != nil && *v.PostId > 0 {
				pid := *v.PostId
				if _, ok := postIdMap[pid]; !ok {
					pids = append(pids, strconv.FormatUint(pid, 10))
					postIdMap[pid] = struct{}{}

					if section == nil && v.Section != nil {
						section = v.Section
					}
				}
			}
		}

		if len(pids) > 0 {
			entries, err := l.getEntryListByIds(strings.Join(pids, ","))
			if err != nil {
				return nil, err
			}

			if len(entries) > 0 {
				idEntryMap := make(map[uint64]*types.KbEntryInfo)
				for _, entry := range entries {
					if entry.Id != nil && *entry.Id > 0 {
						idEntryMap[*entry.Id] = entry
					}
				}

				for pid := range postIdMap {
					if entry, ok := idEntryMap[pid]; ok {
						resp.List = append(resp.List, entry)
					}
				}
				if section != nil {
					resp.Section = &types.SectionInfo{
						Id:       section.Id,
						Title:    section.Title,
						Subtitle: section.Subtitle,
						ImageUrl: section.PicUrl,
					}
				}
			}
		}

		*headers = []*types.Header{
			{
				Key:   "x-class",
				Value: "com.djx.appview.MallForumPage",
			},
		}
	}

	return resp, nil
}

func (l *GetEntryListLogic) getEntryListByIds(ids string) (resp []*types.KbEntryInfo, err error) {
	preload := "blogBook:Id,Title,Slug"
	eagerLoad := "blogBook:blogBookMeta"
	preload += ";blogBookMeta:mediaId,mediaUrl,reviewCount"

	var filters []string
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.PostStatusPublish), 10))
	filters = append(filters, "Id,in:"+ids)

	res, err := l.svcCtx.BlogRpc.GetKBPostListTmp(l.ctx, &blogclient.BaseListReq{
		Preload:   pointy.GetPointer(preload),
		EagerLoad: pointy.GetPointer(eagerLoad),
		Filter:    pointy.GetPointer(strings.Join(filters, ";")),
	})
	if err != nil {
		return nil, err
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			var mediaUrl *string
			var reviewCount *uint32
			if len(v.Meta) > 0 {
				for _, m := range v.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					val := *m.Value
					switch *m.Key {
					case "mediaUrl":
						mediaUrl = pointy.GetPointer(val)
					case "reviewCount":
						if i, err := strconv.ParseInt(val, 10, 32); err == nil {
							reviewCount = pointy.GetPointer(uint32(i))
						}
					}
				}
			}

			resp = append(resp, &types.KbEntryInfo{
				Id:          v.Id,
				Title:       v.Title,
				Slug:        v.Slug,
				ImageUrl:    mediaUrl,
				ReviewCount: reviewCount,
			})
		}
	}

	return resp, nil
}

func (l *GetEntryListLogic) getEntryList(
	page uint64,
	pageSize uint64,
	userId uint64,
	platformId uint32,
	sectionId *uint64,
	sticky *uint32,
) (resp *types.GetEntryListResp, err error) {
	preload := "blogBook:Id,Title,Slug"
	eagerLoad := "blogBook:blogBookMeta"
	preload += ";blogBookMeta:mediaId,mediaUrl,reviewCount"
	filters := []string{"Status,equalTo:" + strconv.FormatInt(int64(globalkey.PostStatusPublish), 10)}
	if sectionId != nil && *sectionId > 0 {
		filters = append(filters, "SectionId,equalTo:"+strconv.FormatUint(*sectionId, 10))
	}
	if sticky != nil && *sticky > 0 {
		filters = append(filters, "Sticky,equalTo:"+strconv.FormatInt(int64(*sticky), 10))
	}

	res, err := l.svcCtx.BlogRpc.GetKBPostListTmp(l.ctx, &blogclient.BaseListReq{
		Offset:     uint32((page - 1) * pageSize),
		Limit:      uint32(pageSize),
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		Sorter:     pointy.GetPointer("Slug"),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(platformId),
	})
	if err != nil {
		return nil, err
	}

	var hasNextPage bool
	var hasPreviousPage bool
	if res.HasNextPage != nil && *res.HasNextPage > 0 {
		hasNextPage = true
	}
	if res.HasPreviousPage != nil && *res.HasPreviousPage > 0 {
		hasPreviousPage = true
	}

	resp = &types.GetEntryListResp{
		BaseListInfo: types.BaseListInfo{
			Current:         page,
			PageSize:        pageSize,
			HasNextPage:     hasNextPage,
			HasPreviousPage: hasPreviousPage,
		},
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			var mediaUrl *string
			var reviewCount *uint32
			if len(v.Meta) > 0 {
				for _, m := range v.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					val := *m.Value
					switch *m.Key {
					case "mediaUrl":
						mediaUrl = pointy.GetPointer(val)
					case "reviewCount":
						if i, err := strconv.ParseInt(val, 10, 32); err == nil {
							reviewCount = pointy.GetPointer(uint32(i))
						}
					}
				}
			}

			resp.List = append(resp.List, &types.KbEntryInfo{
				Id:          v.Id,
				Title:       v.Title,
				Slug:        v.Slug,
				ImageUrl:    mediaUrl,
				ReviewCount: reviewCount,
			})
		}
	}

	return resp, nil
}
